from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
import uuid

db = SQLAlchemy()

class User(db.Model):
    """用户主表"""
    __tablename__ = 'users'
    
    id = db.Column(db.Integer, primary_key=True)
    uuid = db.Column(db.String(36), unique=True, nullable=False, default=lambda: str(uuid.uuid4()))
    username = db.Column(db.String(80), unique=True, nullable=True)  # 用户名（可选）
    email = db.Column(db.String(120), unique=True, nullable=True)    # 邮箱（可选）
    phone = db.Column(db.String(20), unique=True, nullable=True)     # 手机号
    password_hash = db.Column(db.String(255), nullable=True)         # 密码哈希
    nickname = db.Column(db.String(100), nullable=True)              # 昵称
    avatar = db.Column(db.String(255), nullable=True)                # 头像URL
    balance = db.Column(db.Numeric(10, 2), default=0.00, nullable=False)  # 币余额
    status = db.Column(db.Integer, default=1)                        # 状态：1-正常，0-禁用
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    last_login_at = db.Column(db.DateTime, nullable=True)
    
    # 关联关系
    wechat_accounts = db.relationship('WechatAccount', backref='user', lazy=True, cascade='all, delete-orphan')
    login_logs = db.relationship('LoginLog', backref='user', lazy=True, cascade='all, delete-orphan')
    sms_codes = db.relationship('SmsCode', backref='user', lazy=True, cascade='all, delete-orphan')
    
    def set_password(self, password):
        """设置密码"""
        self.password_hash = generate_password_hash(password)
    
    def check_password(self, password):
        """验证密码"""
        if not self.password_hash:
            return False
        return check_password_hash(self.password_hash, password)
    
    def add_balance(self, amount):
        """增加余额"""
        if amount > 0:
            self.balance = (self.balance or 0) + amount
            self.updated_at = datetime.utcnow()
            return True
        return False
    
    def subtract_balance(self, amount):
        """减少余额"""
        if amount > 0 and (self.balance or 0) >= amount:
            self.balance = (self.balance or 0) - amount
            self.updated_at = datetime.utcnow()
            return True
        return False
    
    def get_balance(self):
        """获取余额"""
        return float(self.balance) if self.balance else 0.00
    
    def to_dict(self):
        """转换为字典"""
        return {
            'id': self.id,
            'uuid': self.uuid,
            'username': self.username,
            'email': self.email,
            'phone': self.phone,
            'nickname': self.nickname,
            'avatar': self.avatar,
            'balance': float(self.balance) if self.balance else 0.00,
            'status': self.status,
            'created_at': self.created_at.isoformat() if self.created_at else None,
            'last_login_at': self.last_login_at.isoformat() if self.last_login_at else None
        }

class WechatAccount(db.Model):
    """微信账号表"""
    __tablename__ = 'wechat_accounts'
    
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    openid = db.Column(db.String(100), unique=True, nullable=False)   # 微信openid
    unionid = db.Column(db.String(100), unique=True, nullable=True)   # 微信unionid
    nickname = db.Column(db.String(100), nullable=True)               # 微信昵称
    avatar = db.Column(db.String(255), nullable=True)                 # 微信头像
    subscribe_status = db.Column(db.Integer, default=0)               # 关注状态：1-已关注，0-未关注
    subscribe_time = db.Column(db.DateTime, nullable=True)            # 关注时间
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

class SmsCode(db.Model):
    """短信验证码表"""
    __tablename__ = 'sms_codes'
    
    id = db.Column(db.Integer, primary_key=True)
    phone = db.Column(db.String(20), nullable=False)                  # 手机号
    code = db.Column(db.String(10), nullable=False)                   # 验证码
    purpose = db.Column(db.String(20), nullable=False)                # 用途：login-登录，register-注册
    used = db.Column(db.Boolean, default=False)                       # 是否已使用
    expires_at = db.Column(db.DateTime, nullable=False)               # 过期时间
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)  # 关联用户（可选）
    
    def is_expired(self):
        """检查是否过期"""
        return datetime.utcnow() > self.expires_at
    
    def is_valid(self, code):
        """验证验证码"""
        return not self.used and not self.is_expired() and self.code == code

class WechatQrCode(db.Model):
    """微信扫码登录二维码表"""
    __tablename__ = 'wechat_qr_codes'
    
    id = db.Column(db.Integer, primary_key=True)
    scene_id = db.Column(db.String(100), unique=True, nullable=False)  # 场景值
    ticket = db.Column(db.String(255), nullable=False)                 # 二维码ticket
    qr_code_url = db.Column(db.String(255), nullable=False)            # 二维码URL
    status = db.Column(db.String(20), default='pending')               # 状态：pending-等待扫码，scanned-已扫码，confirmed-已确认，expired-已过期
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)  # 扫码用户ID
    expires_at = db.Column(db.DateTime, nullable=False)                # 过期时间
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    def is_expired(self):
        """检查是否过期"""
        return datetime.utcnow() > self.expires_at

class LoginLog(db.Model):
    """登录日志表"""
    __tablename__ = 'login_logs'
    
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    login_type = db.Column(db.String(20), nullable=False)              # 登录类型：password-密码，sms-短信，wechat-微信
    ip_address = db.Column(db.String(45), nullable=True)               # IP地址
    user_agent = db.Column(db.Text, nullable=True)                     # 用户代理
    device_info = db.Column(db.Text, nullable=True)                    # 设备信息
    success = db.Column(db.Boolean, default=True)                      # 是否成功
    failure_reason = db.Column(db.String(255), nullable=True)          # 失败原因
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

class RefreshToken(db.Model):
    """刷新令牌表"""
    __tablename__ = 'refresh_tokens'
    
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    token = db.Column(db.String(255), unique=True, nullable=False)     # 刷新令牌
    expires_at = db.Column(db.DateTime, nullable=False)                # 过期时间
    revoked = db.Column(db.Boolean, default=False)                     # 是否已撤销
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    
    def is_expired(self):
        """检查是否过期"""
        return datetime.utcnow() > self.expires_at
    
    def is_valid(self):
        """检查是否有效"""
        return not self.revoked and not self.is_expired()